package com.jswdwsx.esign.service

import com.jswdwsx.esign.cloud.enums.FlowStatusEnum
import com.jswdwsx.esign.cloud.enums.toDocNameEnum
import com.jswdwsx.esign.cloud.response.FlowStatusResp
import com.jswdwsx.esign.commom.ResEnum
import com.jswdwsx.esign.controller.request.FlowNotifyReq
import com.jswdwsx.esign.entity.FlowPO
import com.jswdwsx.esign.entity.RequestStatusEnum
import com.jswdwsx.esign.exception.EsignBusinessException
import com.jswdwsx.esign.protocol.response.QueryFileTemplateResp
import com.jswdwsx.esign.repo.FileTemplateRepository
import com.jswdwsx.esign.repo.FlowRepository
import com.jswdwsx.esign.util.json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.slf4j.LoggerFactory.getLogger
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.util.CollectionUtils


@Service
class RequestService(
    private val flowRepository: FlowRepository,
    private val fileTemplateRepository: FileTemplateRepository,
    private val flowService: FlowService,
    private val fileTemplateService: FileTemplateService,
    private val commonHttpClient: OkHttpClient
) {

    private val logger = getLogger(RequestService::class.java)

    @Transactional
    fun completeRequest(notifyReq: FlowNotifyReq): String? {
        notifyReq.flowId?.let {
            val flow = flowRepository.findByEsignFlowId(it)
                ?: throw EsignBusinessException(ResEnum.FlowDoesNotExist)
            finish(flow, notifyReq.flowStatus)

            callBusinessBack(flow, notifyReq.statusDescription)
            return flow.request.id
        }
        logger.error("E签宝回调参数有误，签署流程回调flowId为空")
        throw EsignBusinessException(ResEnum.ParamErr)
    }

    /**
     * 结束签署流程（修改状态、成功则下载已签署流程文件）
     */
    fun finish(flow: FlowPO, flowStatus: Int?) {
        // 流程状态,0->草稿 1->签署中  不管
        if (flowStatus == 0 || flowStatus == 1) {
            return
        }

        // 2已完成: 所有签署人完成签署； 3已撤销: 发起方撤销签署任务； 4已终止: 至少一个签署人拒签或通过重试不可恢复的签署失败 ； 5已过期: 超时未签署 ；6: 已删除；7：已拒签
        if (flowStatus != 2) {
            flow.status = FlowStatusEnum.Fail
        } else {

            // 如果没有下载
            if (CollectionUtils.isEmpty(flow.ossFileUrl)) {
                val ossFileUrl = flowService.downloadFlowFile(flow.esignFlowId)
                flow.status = FlowStatusEnum.Success
                flow.ossFileUrl = ossFileUrl
                flow.request.status = RequestStatusEnum.Success
            }
        }
    }

    /**
     * 回调业务系统
     */
    private fun callBusinessBack(flow: FlowPO, statusDescription: String?) {
        flow.request.notifyUrl?.let {

            val req = FlowStatusResp(
                appSerialNumber = flow.request.appSerialNumber,
                flowStatus = flow.status,
                desc = statusDescription,
                docsUrl = flow.ossFileUrl?.associateBy(
                    { doc -> doc.fileName.toDocNameEnum() },
                    { doc -> doc.fileUrl })
            )
            logger.info("回调业务系统：requestId:[${flow.request.id}]，url:[$it],请求体：[$req]")
            try {

                val request = Request.Builder()
                    .url(it)
                    .post(req.json().toRequestBody())
                    .build()

                commonHttpClient.newCall(request).execute()

            } catch (e: Exception) {
                logger.error("签署成功但是回调业务系统失败了，requestId:[${flow.request.id}],$e")
            }
        }
    }

    fun queryParams(flowTemplateId: String): List<QueryFileTemplateResp> {
        return fileTemplateRepository.findAllByFlowTemplateId(flowTemplateId).map {
            fileTemplateService.queryTemplate(it.fileTemplateId)
        }
    }

    companion object {
        val JSON = "application/json; charset=utf-8".toMediaType()
    }
}
